#include "ClipGeomtryView.h"

#include <QVBoxLayout>
#include <QFontDatabase>
#include <QPainter>
#include <QSize>
#include <QByteArray>
#include <QValidator>
#include <QIntValidator>
#include <QDoubleValidator>
#include <QRegularExpressionValidator>
#include <QRegularExpression>
#include <QStringList>
#include <QMessageBox>
#include <QPainterPath>
#include <QDebug>
#include <QString>
#include <QPoint>

#include <QLabel>

#include <QPalette>

#include <QTimer>



#include "../IdRootMenu.h"
#include "../MenuIdConvert.h"



#include "../tpop/PWindowEditTool.h"
#include "../tpop/PWindowAffineTool.h"
#include "../tpop/PWindowDrawType.h"
#include "../../uitools/vhc/constview4fun.h"
#include "../../uitools/vhc/constview4id.h"


#include "mcore/tools/setting/KeToolSettings.h"
#include "mcore/tools/EditWidget.h"
#include "mcore/tools/normal/EditTool.h"
#include "mcore/tools/affine/AffinePan.h"
#include "mcore/tools/affine/AffineRotate.h"
#include "mcore/tools/affine/AffineShear.h"
#include "mcore/tools/affine/AffineZoomScale.h"
#include "mcore/tools/line/LineSlideTool.h"
#include "mcore/tools/vertex/VertexAddTool.h"

#include "mcore/map/EarthMapConst.h"

#include "ClipToolBar.h"

#include <geostyle/xmls/SldParser.h>


namespace kepen {
namespace core {

ClipGeomtryView::ClipGeomtryView(QWidget *parent,KeSysSetting *config)
    : QVBoxLayout{parent}
,sysConfig(config)
{
    setDirection(QBoxLayout::TopToBottom);
    setSpacing(0);
    setContentsMargins(0, 0, 0, 0);
    setAlignment(Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop);





    mapSurface = dynamic_cast<kepen::core::MapObject*>(parent);
    EditWidget*ewPtr = mapSurface->getEditWidgetSingleton();
    KeToolSettings *keSettingRR2 = ewPtr->getMapToolSettings();
    fontLabel.setPointSize(TextSize_Tool);

    int fontId = QFontDatabase::addApplicationFont(config->configView()->fileIconFont);
    QString fontName = QFontDatabase::applicationFontFamilies(fontId).at(0);
    QFont fontIcon = QFont(fontName);
    fontIcon.setPointSize(TextSize_IconFont);

    thirdFontIcon = fontIcon;

    keSettingRR2->m_visibleVertexIndex = false;

    lpContextData = new ClipContextData();
    lpContextData->ewPtr = ewPtr;

    int arrHead[]={  0x990002,
        Goback_BarBtnId,
        0x990002,
        Apply_Commit_BtnId,
        0x990012,
        ClipGeometry_Radio,
        0x990008,
        CleanTopLayer,
        0x990008,
        Option_VisibleVertexIndex,
        0x990004
    };
    int arrEdit[]={  0x990002,
        ClipBrushType_Combox,
        0x99000f,
        AffineTool_Combox,
        0x99000f,
        EditTool_Combox,
        0x990004
    };
    int contA = sizeof(arrHead)/sizeof(arrHead[0]);
    int contB = sizeof(arrEdit)/sizeof(arrEdit[0]);

    toolBarHead = new ClipToolBar(parent,this,arrHead,contA);
    toolBarEdit = new ClipToolBar(parent,this,arrEdit,contB);

    //本控件继承自QVBoxLayout
    addWidget(toolBarHead);
    addWidget(toolBarEdit);


    kepen::core::Graphic * gr = ewPtr->getEditGraphicR0();
    std::unique_ptr<kepen::core::Graphic> grC = gr->clone();

    std::unique_ptr<geos::geom::Geometry> c = gr->getGeom()->clone();

    std::unique_ptr<geos::geom::Polygon> poly = initRectRence(c.get());


    mGeomBase.reset(c.release());


    // qDebug().noquote() <<"-------File:" <<__FILE__ <<",Line:"<<__LINE__ << "  "<<poly->toString();

    gr->setGeom(std::move(poly));

    kepen::sld::SldParser parserSld;

    QString cssPoly("{polygonOptions:{strokeWidth:2dp,strokeColor:#666,fillColor:#a0121212}}");
    std::unique_ptr<kepen::sld::UserStyle> stylePoly = parserSld.ReadUserStyleCss(cssPoly);

    gr->setStyle(std::move(stylePoly));
    gr->setFence(true);

    kepen::core::GraphicsLayer * gLayer =  ewPtr->getEditGrapicLayer();
    gLayer->addGraphic(std::move(grC));

    onAffineToolSelectedImpl(EditTool_Zoom);
    // mapSurface->repaint();

}

ClipGeomtryView::~ClipGeomtryView()
{
    // QLayoutItem *child;
    // QWidget *wg_ch;

    // mapSurface->setActivateTool(NULL);//tool的parent是本类，没有意义，只是添乱
    //奇怪，ProtactorToolView析构可以，这个，就是不行，
    //现象：进入此页面，点击平移工具，然后退出(点击应用程序右上角退出按钮)，系统崩溃
    //原因竟然是，tool的parent 必须是本类，就OK，否则崩溃

    // 是有必要的，因为：child->parent === mapSurface,不是本类，本类是QVBoxLayout，不是QWidget
    // while ((child = takeAt(0)) != nullptr) {
    //     wg_ch = child->widget();
    //     if(wg_ch)
    //         delete child->widget();
    //     delete child;
    // }

    delete lpContextData;
    lpContextData = NULL;
}


int ClipGeomtryView::onComboxClicked(int id,int flag,const QPoint &point)
{

    if(EditTool_Combox == id){

        if(Pos_ComboBox_Right == flag)
        {
            QWidget *parent = toolBarEdit;
            int checkedId = lpContextData->nEditTool;

            PWindowEditTool * wPopup  = new PWindowEditTool(parent,checkedId,thirdFontIcon);
            connect(wPopup, SIGNAL(selectedEditToolSignals(QWidget*,int)),
                    this,SLOT(onSelectedEditTool(QWidget*,int)),
                    Qt::ConnectionType(Qt::DirectConnection| Qt::SingleShotConnection));

            wPopup->show();
            wPopup->move(point);

        }else
        {
            int checkedId = lpContextData->nEditTool_last;
            onEditToolSelectedImpl(checkedId);
        }
    }else if(AffineTool_Combox == id){

        if(Pos_ComboBox_Right == flag)
        {
            QWidget *parent = toolBarEdit;
            int checkedId = lpContextData->nEditTool;

            PWindowAffineTool * wPopup  = new PWindowAffineTool(parent,checkedId,thirdFontIcon);
            connect(wPopup, SIGNAL(selectedAffineToolSignals(QWidget*,int)),
                    this,SLOT(onSelectedAffineTool(QWidget*,int)),
                    Qt::ConnectionType(Qt::DirectConnection| Qt::SingleShotConnection));

            wPopup->show();
            wPopup->move(point);

        }else
        {
            int checkedId = lpContextData->nAffineTool_last;
            onAffineToolSelectedImpl(checkedId);
        }
    }else if(ClipBrushType_Combox == id){

        if(Pos_ComboBox_Right == flag)
        {
            QWidget *parent = toolBarEdit;
            int checkedId = lpContextData->nDrawTool;

            PWindowDrawType * wPopup  = new PWindowDrawType(parent,checkedId,id,thirdFontIcon);
            connect(wPopup, SIGNAL(selectedDrawToolSignals(QWidget*,int,int)),
                    this,SLOT(onSelectedDrawTool(QWidget*,int,int)),
                    Qt::ConnectionType(Qt::DirectConnection| Qt::SingleShotConnection));

            wPopup->show();
            wPopup->move(point);

        }else
        {
            int checkedId = lpContextData->nDrawTool_last;
            onDrawToolSelectedImpl(checkedId);
        }
    }
    return ViewClickFlag_RepaintRoot;
}

int ClipGeomtryView::onBtnClicked(int id)
{
    int retFlag = ( IS_Close_Tab(id))?ViewClickFlag_Go:0;
    if(IS_Close_Tab(id))
    {
        mapSurface->setActivateTool(NULL);
        doViewGoback();


        QTimer::singleShot(TimeoutClickFree,this,SLOT(timeoutClosedThiz()));

    }else if(ClipGeometry_Radio == id)
    {

        EditWidget * ewPtr = mapSurface->getEditWidgetSingleton();
        kepen::core::Graphic * gr = ewPtr->getEditGraphicR0();

        lpContextData->convertTypeClip();

        // toolBarHead->repaint();

        bool isFence =  ClipGeometry_Inter == lpContextData->nTypeClip;
        gr->setFence(isFence);
        mapSurface->repaint();
    }else if(Option_VisibleVertexIndex ==id)
    {
         EditWidget * ewPtr = mapSurface->getEditWidgetSingleton();
        KeToolSettings *keSettingRR2 = ewPtr->getMapToolSettings();
        keSettingRR2->m_visibleVertexIndex = !keSettingRR2->m_visibleVertexIndex;
        mapSurface->repaint();
    }else if(Apply_Commit_BtnId ==  id)
    {
        doClipGeometry();
    }
    return retFlag;
}

void ClipGeomtryView::repaintToolBar()
{

}

std::unique_ptr<geos::geom::Polygon> ClipGeomtryView::initRectRence(const geos::geom::Geometry  *geom)
{
    std::size_t numPoints = 5,dim = MyGeomOutputDimension;
    geos::geom::GeometryFactory::Ptr gf = geos::geom::GeometryFactory::create();
    const geos::geom::Envelope* env = geom->getEnvelopeInternal();
    double xmin,xmax,ymin,ymax;
    xmin = env->getMinX();
    xmax = env->getMaxX();
    ymin = env->getMinY();
    ymax = env->getMaxY();
    auto coords = geos::detail::make_unique<geos::geom::CoordinateSequence>(numPoints,dim);

    coords->setOrdinate(0,0,xmin);
    coords->setOrdinate(0,1,ymin);

    coords->setOrdinate(1,0,xmin);
    coords->setOrdinate(1,1,ymax);

    coords->setOrdinate(2,0,xmax);
    coords->setOrdinate(2,1,ymax);

    coords->setOrdinate(3,0,xmax);
    coords->setOrdinate(3,1,ymin);

    coords->setOrdinate(4,0,xmin);
    coords->setOrdinate(4,1,ymin);

    std::unique_ptr<geos::geom::LinearRing> _ring = gf->createLinearRing(std::move(coords));
    return gf->createPolygon(std::move(_ring));
    /*
 * 不能这样构建，否则，affineTool(平移，缩放)找不到边界点，边界点在（-180,-90;180,90）
    xmin = XMin_Coord;
    xmax = XMax_Coord;
    ymin = YMin_Coord;
    ymax = YMax_Coord;

    std::unique_ptr<geos::geom::CoordinateSequence> vs = geos::detail::make_unique<geos::geom::CoordinateSequence>(numPoints,dim);

    vs->setOrdinate(0,0,xmin);
    vs->setOrdinate(0,1,ymin);

    vs->setOrdinate(1,0,xmax);
    vs->setOrdinate(1,1,ymin);

    vs->setOrdinate(2,0,xmax);
    vs->setOrdinate(2,1,ymax);

    vs->setOrdinate(3,0,xmin);
    vs->setOrdinate(3,1,ymax);

    vs->setOrdinate(4,0,xmin);
    vs->setOrdinate(4,1,ymin);

    std::unique_ptr<geos::geom::LinearRing> _shell = gf->createLinearRing(std::move(vs));

    std::vector<std::unique_ptr<LinearRing>> holes;
    holes.push_back(std::move(_ring));

    return gf->createPolygon(std::move(_shell),std::move(holes));
*/
}


void ClipGeomtryView::onSelectedEditTool(QWidget *dlg,int id)
{
    onEditToolSelectedImpl(id);

    dlg->deleteLater();
}

void ClipGeomtryView::onSelectedAffineTool(QWidget *dlg,int id)
{
    onAffineToolSelectedImpl(id);

    dlg->deleteLater();
}

void ClipGeomtryView::onSelectedDrawTool(QWidget *dlg,int id,int data)
{
    if(ClipBrushType_Combox == data)
    {

        onDrawToolSelectedImpl(id);
    }

    dlg->deleteLater();
}

void ClipGeomtryView::timeoutClosedThiz()
{
    Q_EMIT onViewTabClosedSignals(this);
}

void ClipGeomtryView::onDrawCompletedHandler(DrawTool *tool)
{
    std::unique_ptr<geos::geom::Geometry> geomNew = tool->getDrawCompleted();
    if(geomNew && geomNew.get() && false == geomNew->isEmpty())
    {
        EditWidget * ewPtr = mapSurface->getEditWidgetSingleton();
        kepen::core::Graphic * gr = ewPtr->getEditGraphicR0();
        bool isFence =  ClipGeometry_Inter == lpContextData->nTypeClip;
        gr->setGeom(std::move(geomNew));
        gr->setFence(isFence);

        mapSurface->repaint();

    }
}

void ClipGeomtryView::actEditTool(int id, bool checkView)
{
    // MapObject * mapSurface =mapObj;
    if(false == IS_EditTool_Affine(id))
    {
        kepen::core::EditWidget* ew = mapSurface->getEditWidgetSingleton();
        ew->getEditPointLayer()->clearData();
    }

    if(EditTool_Vector == id)
    {
        kepen::core::EditTool *tool = new  kepen::core::EditTool(this);
        tool->activate(mapSurface,kepen::core::SnapOption::Any,checkView);


    }else if(EditTool_Pan == id){
        kepen::core::AffinePan *tool = new  kepen::core::AffinePan(this);
        tool->activate(mapSurface);
    }else if(EditTool_Zoom == id){
        kepen::core::AffineZoomScale *tool = new  kepen::core::AffineZoomScale(this);
        tool->activate(mapSurface);
    }else if(EditTool_Rotate == id){
        kepen::core::AffineRotate *tool = new  kepen::core::AffineRotate(this);
        tool->activate(mapSurface);
    }else if(EditTool_Shear == id){
        kepen::core::AffineShear *tool = new  kepen::core::AffineShear(this);
        tool->activate(mapSurface);
    }else if(EditTool_LineSlide == id){
        kepen::core::LineSlideTool *tool = new  kepen::core::LineSlideTool(this);
        tool->activate(mapSurface,kepen::core::LineSlideTool::SegmentDragDefine::SlideProfiling);
    }else if(EditTool_LineExtrude == id){
        kepen::core::LineSlideTool *tool = new  kepen::core::LineSlideTool(this);
        tool->activate(mapSurface,kepen::core::LineSlideTool::SegmentDragDefine::ByExtrude);
    }else if(Edit_AddVertexOnLine == id){
        kepen::core::VertexAddTool *tool = new  kepen::core::VertexAddTool(this);
        tool->activate(mapSurface);
    }

    mapSurface->repaint();
}

void ClipGeomtryView::onEditToolSelectedImpl(int id)
{
    if(id != MenuId_None)
    {

        int val = lpContextData->nEditTool;
        if(id == val)
        {
            lpContextData->setEditTool(MenuId_None);
            mapSurface->setActivateTool(NULL);
            mapSurface->repaint();
        }else
        {
            // kepen::core::EditWidget* ew = mapSurface->getEditWidgetSingleton();
            lpContextData->setEditTool(id);
            //ew->
            actEditTool(id,false);
            //mapSurface->repaint();
        }

    }
}

void  ClipGeomtryView::onAffineToolSelectedImpl(int id)
{
    if(id != MenuId_None)
    {

        int val = lpContextData->nAffineTool;
        if(id == val)
        {
            lpContextData->setAffineTool(MenuId_None);
            mapSurface->setActivateTool(NULL);
            mapSurface->repaint();
        }else
        {
            // kepen::core::EditWidget* ew = mapSurface->getEditWidgetSingleton();
            lpContextData->setAffineTool(id);

            actEditTool(id,false);
            //mapSurface->repaint();
        }

    }
}

void ClipGeomtryView::onDrawToolSelectedImpl(int id)
{

    if(id != MenuId_None){
        int val = lpContextData->nDrawTool;
        if(id == val)
        {
            lpContextData->setDrawTool(MenuId_None);
            mapSurface->setActivateTool(NULL);
            mapSurface->repaint();
        }else{
            kepen::core::DrawTool::DrawType nDrawType = MenuIdConvert::GetDrawTypeByID(id);
            lpContextData->setDrawTool(id);
            doActDrawToolImpl(nDrawType);
        }
    }else
    {
        // lpContextData->setDrawTool(MenuId_None);
        // mapSurface->setActivateTool(NULL);
        mapSurface->repaint();
    }

}

void ClipGeomtryView::doActDrawToolImpl(kepen::core::DrawTool::DrawType nDrawType)
{
    kepen::core::MapObject * mapObj = mapSurface;
    kepen::core::DrawTool *tool = mapObj->createDrawTool(this,nDrawType,kepen::core::DrawTool::Draw4Shape::NewGeometry);
    // tool->activate(mapObj);

    connect(tool, SIGNAL(onDrawCompletedSignals(kepen::core::DrawTool*)),
            this,SLOT(onDrawCompletedHandler(kepen::core::DrawTool*)),
            Qt::ConnectionType(Qt::DirectConnection|Qt::SingleShotConnection));
    mapObj->repaint();
}

void ClipGeomtryView::doClipGeometry()
{
    EditWidget * ewPtr = mapSurface->getEditWidgetSingleton();
    kepen::core::Graphic * gr = ewPtr->getEditGraphicR0();
    const geos::geom::Geometry *geom = gr->getGeom();
    if(geom && false == geom->isEmpty())
    {

        geos::geom::GeometryTypeId tid = geom->getGeometryTypeId();
        if(geos::geom::GeometryTypeId::GEOS_POLYGON == tid)
        {
            GraphicsLayer *gLayer = ewPtr->getEditGrapicLayer();
            std::size_t count = gLayer->getGraphicCount();
            if(count > 0)
            {
                const kepen::core::Graphic * g = gLayer->getGraphicN(0);
                const geos::geom::Geometry *geomSrc = g->getGeom();
                if(geomSrc && false == geomSrc->isEmpty())
                {
                    const geos::geom::Polygon *poly =dynamic_cast<const geos::geom::Polygon*>(geom);
                    int tt = lpContextData->nTypeClip;
                    if(ClipGeometry_Inter == tt)
                    {
                        std::unique_ptr<geos::geom::Geometry> result = geomSrc->intersection(poly);
                        gLayer->updateGeometry(0,std::move(result));
                    }else
                    {
                        std::unique_ptr<geos::geom::Geometry> result = geomSrc->symDifference(poly);
                        gLayer->updateGeometry(0,std::move(result));
                    }

                    mapSurface->repaint();
                }

            }




        }
    }

}

void ClipGeomtryView::doViewGoback()
{
    EditWidget * ewPtr = mapSurface->getEditWidgetSingleton();
    kepen::core::Graphic * gr_edit = ewPtr->getEditGraphicR0();
    GraphicsLayer *gLayer = ewPtr->getEditGrapicLayer();
    std::size_t count = gLayer->getGraphicCount();
    if(count > 0)
    {
        const kepen::core::Graphic * g = gLayer->getGraphicN(0);

        std::unique_ptr<sld::UserStyle> style = g->getStyle()->clone();

        const geos::geom::Geometry *geomSrc = g->getGeom();
        if(geomSrc && false == geomSrc->isEmpty())
        {
            std::unique_ptr<geos::geom::Geometry> result = geomSrc->clone();

            gr_edit->setGeom(std::move(result));

        }else
        {
            gr_edit->setNullGeometry();
        }

        kepen::sld::SldParser parserSld;
        QString cssPoly("{polylineOptions:{strokeWidth:2dp,strokeColor:#FF69B4}}");
        std::unique_ptr<kepen::sld::UserStyle> stylePoly = parserSld.ReadUserStyleCss(cssPoly);
        gr_edit->setStyle(std::move(stylePoly));
        // gr_edit->setStyle(std::move(style));
    }



    gLayer->clearGraphic();

    gr_edit->setFence(false);


    mapSurface->repaint();

}


}
}
